package com.example.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphO;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author: 21050134
 * @date: 2023/10/10 17:37
 * @description:
 */
@RestController
@Slf4j
public class SentinelFlowLimitController {
	@Value("${server.port}")
	private String serverPort;

	@GetMapping("/testA")
	public String testA() {
		//return "服务访问成功------testA";
		return testAbySphU();
	}


	@GetMapping("/testB")
	public String testB() {
		//return "服务访问成功------testB";
		return testBbySphO();
	}

	/**
	 * 通过SphU 手动定义资源
	 *
	 * @return
	 */
	@GetMapping("/testAbySphU")
	public String testAbySphU() {
		Entry entry = null;
		try {
            entry = SphU.entry("testAbySphU");
            //业务逻辑开始
			log.info("服务访问成功--------testA:" + serverPort );
			return "服务访问成功--------testA:" + serverPort;
			//业务逻辑结束
		}catch (BlockException e){
            //流控逻辑处理-开始
			log.info("testA服务被限流");
			return "testA服务被限流";
			//流控逻辑处理 - 结束
		}finally {
			if(entry!=null){
				entry.exit();
			}
		}
	}

	/**
	 * 通过SphO 手动定义资源
	 *
	 * @return
	 */
	@GetMapping("/testBbySphO")
	public String testBbySphO() {
		if(SphO.entry("testBbySphO")){
			try {
				// 务必保证finally会被执行
				log.info("服务访问成功--------testB:" + serverPort );
				return "服务访问成功--------testB:" + serverPort;
			}finally {
				SphO.exit();
			}
		}else{
			// 资源访问阻止，被限流或被降级
            //流控逻辑处理-开始
			log.info("testB服务被限流");
			return "testB服务被限流";
			//流控逻辑处理 - 结束
		}

	}

	@GetMapping("/testC")
	@SentinelResource(value = "testCbyAnnotation")  //通过注解定义资源
	public String testC() {
		log.info("服务访问成功--------testC:" + serverPort );
		return "服务访问成功--------testC:" + serverPort;
	}


	/**
	 * 通过 Sentinel 控制台定义流控规则
	 *
	 * @return
	 */
	@GetMapping("/testD")
	@SentinelResource(value = "testD-resource",blockHandler = "blockHandlerTestD") //通过注解定义资源
	public String testD() {
		initFlowRules(); //调用初始化流控规则的方法
		log.info("服务访问成功--------testD:" + serverPort );
		return "服务访问成功--------testD:" + serverPort;
	}

	public String blockHandlerTestD(BlockException e){
		log.info(Thread.currentThread().getName() +"TestD服务访问失败! 您已被限流，请稍后重试");
		return "TestD服务访问失败! 您已被限流，请稍后重试";
	}


	private static void initFlowRules(){
        List<FlowRule> rules = Lists.newArrayList();
        //定义后一个限流规则对象
		FlowRule rule = new FlowRule();
		//资源名称
		rule.setResource("testD-resource");
		//限流阈值的类型
		rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
		//设置QPS的阈值
		rule.setCount(2);
		rules.add(rule);
		//定义限流规则
		FlowRuleManager.loadRules(rules);

	}

}
